package app;
import fantasma.Fantasmas;
import interfaces.IControlador;
import interfaces.IDibujable;
import interfaces.IFantasma;
import interfaces.ILaberinto;
import interfaces.IObservable;
import interfaces.IObservador;
import interfaces.IPacman;
import interfaces.ISuperficieDeDibujo;
import interfaces.IVista;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import laberinto.Fruta;
import laberinto.Niveles;
import personajes.NullPacman;
import utilidades.Constantes;
import utilidades.Dormir;


/**
 * Esta clase es el componente central de la aplicación
 * 
 * @author diego
 * 
 */

public class Juego implements IObservador{
	
	private List<IVista> vistasXML = new LinkedList<IVista>();
	private int maximaCantidadDeTicks;
	private int iteracion;
	private IPacman pacman;
	private Fantasmas fantasmas;
	private Fruta fruta;
	private Niveles<ILaberinto> nivelesLogicos;
	private IObservable observable;
	private ILaberinto nivelActual;
	private ISuperficieDeDibujo superficieDeDibujo;
	private List<IDibujable> dibujables = new ArrayList<IDibujable>();
	private IControlador controladorXML;
	private List<Niveles<IDibujable>> coleccionDeNivelesDeDibujables = new ArrayList<Niveles<IDibujable>>();
	
	/**
	 * @param controladores coleccion de modulos que se ocupan de la entrada de información
	 * @param vistas colección de los modulos que se ocupan de la salida de la información
	 */
	public Juego(IPacman pacman, ILaberinto laberinto,
			List<IControlador> controladores, List<IVista> vistas,
			int maximaCantidadDeTicks) {
		this.vistasXML = vistas;
		this.maximaCantidadDeTicks = maximaCantidadDeTicks;
		this.pacman = pacman;
		this.fantasmas = laberinto.obtenerFantasmas();
		this.iteracion = 1;
				
	}
	public Juego(Fantasmas fantasmas,
			List<IControlador> controladores, List<IVista> vistas,
			int maximaCantidadDeTicks) {
		this.vistasXML = vistas;
		this.maximaCantidadDeTicks = maximaCantidadDeTicks;
		this.pacman = new NullPacman();
		this.fantasmas = fantasmas;
		this.iteracion = 1;
	}

	public Juego(Niveles<ILaberinto> niveles,IPacman pacman, ILaberinto laberinto,
			List<IControlador> controladores, List<IVista> vistas,
			int maximaCantidadDeTicks) {
		this.vistasXML = vistas;
		this.maximaCantidadDeTicks = maximaCantidadDeTicks;
		this.pacman = pacman;
		this.fantasmas = laberinto.obtenerFantasmas();
		this.iteracion = 1;
		this.nivelesLogicos = niveles;
	}

	public Juego(IPacman pacman,Niveles<ILaberinto> nivelesLogicos,Niveles<IVista> nivelesVisuales,
			List<IControlador> controladores, List<IVista> vistas,
			int maximaCantidadDeTicks) {
		this.vistasXML = new LinkedList<IVista>();
		this.vistasXML.add( nivelesVisuales.siguienteNivel() );
		this.maximaCantidadDeTicks = maximaCantidadDeTicks;
		this.pacman = pacman;
		this.nivelActual= nivelesLogicos.siguienteNivel();
		this.fantasmas = nivelActual.obtenerFantasmas();
		this.iteracion = 1;
		this.nivelesLogicos = nivelesLogicos;
		this.observable=nivelActual;
		this.observable.agregar(this);
	}
	public Juego(ISuperficieDeDibujo superficieDeDibujo,int maximaCantidadDeTicks){
		this.superficieDeDibujo=superficieDeDibujo;
		this.maximaCantidadDeTicks = maximaCantidadDeTicks;
	}
	
	public Juego(int maximaCantidadDeTicks){
		this.maximaCantidadDeTicks = maximaCantidadDeTicks;
	}
	
	public void agregarFantasmas(Fantasmas fantasmas){
		this.fantasmas=fantasmas;
	}
	
	public void agregarPacman(IPacman pacman){
		this.pacman=pacman;
	}
	
	public void agregarVistasXML(List<IVista> vistasXML){
		this.vistasXML = vistasXML;
	}
	
	public void agregarControladorXML(IControlador controladorXML){
		this.controladorXML=controladorXML;
	}
	
	public void agregarNivelesLogicos(Niveles<ILaberinto> nivelesLogicos){
		this.nivelesLogicos=nivelesLogicos;
	}

	public void agregarNivelesDelDibujable(Niveles<IDibujable> nivelesDelDibujable){
		this.coleccionDeNivelesDeDibujables.add(nivelesDelDibujable);
		this.dibujables.add(nivelesDelDibujable.nivelActual());//siguienteNivel());
	}


	private void actualizarXMLControlador() {
		if(controladorXML!=null){
		   controladorXML.actualizar(iteracion);
		}
	}
	private void actualizarXMLVista() {
		for(IVista vistaXML : vistasXML){
		   vistaXML.actualizar(iteracion);
		}
	}
	
	private void actualizarObjetosVivos() {		
		if(!pacman.esUnPacmanNulo()){
			pacman.vivir(iteracion);
		}

		if(fruta != null){
			fruta.vivir();
		}
		for (IFantasma fantasma : fantasmas.obtenerArrayListDeFantasmas()){
			fantasma.vivir(pacman);
		}
	}
	
	private void dibujar() {
		superficieDeDibujo.limpiar();

		for(IDibujable dibujable : dibujables){
			dibujable.dibujar(superficieDeDibujo.obtenerGrafico());
		}
		
		superficieDeDibujo.actualizar();
	}



	public boolean finalDelJuego() {
		return pacman.estaMuerto();
	}
	public IPacman obtenerPacman(){
		return pacman;
	}
	public void agregarFruta(Fruta nuevaFruta) {
		fruta = nuevaFruta;
	}
	public Fruta obtenerFruta() {
		return fruta;
	}
	public void iniciarJuego(){
		if(this.superficieDeDibujo!=null){
			nivelActual= nivelesLogicos.nivelActual();
			this.observable=nivelActual;
		}
		
		
		iteracion = 1;
		vista.Audio.playOnTop(Constantes.CLIP_INICIO); 
		boolean pacmanDisponible = ((!pacman.esUnPacmanNulo()) || (!pacman.estaMuerto()));
		boolean hayBolitas = (nivelActual != null) && nivelActual.tieneBolitas();
		while(iteracion<maximaCantidadDeTicks+1 && pacmanDisponible && hayBolitas){

			actualizarXMLControlador();
		    	actualizarObjetosVivos();
			if(superficieDeDibujo!=null){
		    	  dibujar();
			}			
			actualizarXMLVista();
			pacmanDisponible =!pacman.estaMuerto();
			hayBolitas = nivelActual.tieneBolitas();
			Dormir.dormir(Constantes.TIEMPO_ENTRE_CICLOS_DE_EJECUCION);
			iteracion++;

			if (iteracion == 2){
				Dormir.dormir(Constantes.TIEMPO_INTRO);
			}
		}
	}
	@Override
	public void actualizar() {}
}
